使用函数 cv2.imread(arg1,arg2) 读入图像。
arg1是这幅图像在此程序的相对路径或者系统绝对路径
arg2是要告诉函数应该如何读取这幅图片,通常有以下几个选项。
• cv2.IMREAD_COLOR:读入一副彩色图像。图像的透明度会被忽略, 这是默认参数。 (可以简写为1)
• cv2.IMREAD_GRAYSCALE:以灰度模式读入图像 (可以简写为0)
• cv2.IMREAD_UNCHANGED:读入一幅图像,并且包括图像的 alpha 通道 (可以简写为-1)
警告:就算图像的路径是错的,OpenCV 也不会提醒你的,但是当你使用命 令print img时得到的结果是None。
使用函数 cv2.imshow(arg1,arg2) 显示图像。窗口会自动调整为图像大小。
第一 个参数是窗口的名字,第二个我参数是我们的图像。你可以创建多个窗口,但是窗口名字不能重复。
使用函数 cv2.imwrite(arg1,arg2) 来保存一个图像。
第一个参数是文件名,第二个参数是你要保存的图像
# -*- coding: utf-8 -*
import numpy as np
import cv2
img = cv2.imread('image/messi5.jpg',0)
cv2.imshow('image',img)
cv2.imwrite('messigray.png',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
图像的属性包括:行,列,通道,图像数据类型,像素数目等
使用函数img.shape 可以获取图像的形状。他的返回值是一个包含行数,列数, 通道数的元组。
可以看到如果图像是灰度图,返回值仅有行数和列数。所以通过检查这个返回值 就可以知道加载的是灰度图还是彩色图。
# -*- coding: utf-8 -*
import numpy as np
import cv2
img1 = cv2.imread('image/bg.png',1)
img2 = cv2.imread('image/bg.png',0)
img3 = cv2.imread('image/bg.png',-1)
print(img1.shape)
print(img2.shape)
print(img3.shape)
img.size 可以返回图像的像素数目
# -*- coding: utf-8 -*
import numpy as np
import cv2
img1 = cv2.imread('image/bg.png',1)
img2 = cv2.imread('image/bg.png',0)
img3 = cv2.imread('image/bg.png',-1)
print(img1.size)
print(img2.size)
print(img3.size)
img.dtype 返回的是图像的数据类型.
# -*- coding: utf-8 -*
import numpy as np
import cv2
img1 = cv2.imread('image/bg.png',1)
img2 = cv2.imread('image/bg.png',0)
img3 = cv2.imread('image/bg.png',-1)
print(img1.dtype)
print(img2.dtype)
print(img3.dtype)
在debug时 img.dtype 非常重要。因为在 OpenCVPython 代码中经常出现数据类型的不一致。
Opencv默认的彩色图像的颜色空间是BGR,有时针对特定的库需要进行一些改变。
我们使用 cv2.cvtColor(image,flag)进行颜色空间转换
其中image是要转换的图像, flag就是转换类型。
cvtColor()支持多种颜色空间之间的转换,常用的转换类型和转换码如下:
COLOR_BGR2RGB
COLOR_BGRA2RGBA
COLOR_RGB2RGBA
COLOR_RGBA2RGB
COLOR_RGB2GRAY
COLOR_BGR2GRAY
# -*- coding: utf-8 -*
import numpy as np
import cv2
img1 = cv2.imread('image/messi5.jpg')
cv2.imshow('BGR', img1)
img2 = cv2.cvtColor(img1,cv2.COLOR_BGR2RGB)
cv2.imshow('RGB', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
BGR图
RGB图
可以看到通道顺序从BRG变成了RGB
有时我们需要对 BGR 三个通道分别进行操作。这是你就需要把 BGR 拆 分成单个通道。有时你需要把独立通道的图片合并成一个 BGR 图像。你可以 这样做:
使用cv2.split(img)函数 img是你要分离通道的图片
# -*- coding: utf-8 -*
import numpy as np
import cv2
img = cv2.imread('image/messi5.jpg')
cv2.imshow('BRG',img)
b,g,r=cv2.split(img)
cv2.imshow('B',b)
cv2.imshow('G',g)
cv2.imshow('R',r)
cv2.waitKey(0)
cv2.destroyAllWindows
我们可以看到通道分离之后每个通道均为灰度图
b = cv2.split(img)[0]
g = cv2.split(img)[1]
r = cv2.split(img)[2]
merged = cv2.merge([b,g,r]) #前面分离出来的三个通道
对分离的通道进行操作之后我们还可以把他进行合并,恢复成一张BGR图。
可以使用函数 cv2.add() 将两幅图像进行加法运算
也可以直接使 用 numpy,res=img1+img
两幅图像的大小,类型必须一致,或者第二个 图像可以使一个简单的标量值
注意opencv的加法是饱和操作,而numpy是一种膜操作
x = np.uint8([250])
y = np.uint8([10])
print cv2.add(x,y) # 250+10 = 260 => 255
[[255]]
print x+y # 250+10 = 260 % 256 = 4
[4]
这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混 合或者透明的感觉。图像混合的计算公式如下:
g (x) = (1−α) v(x) + α u(x)
cv2.addWeighted( )
import cv2
import numpy as np
img1=cv2.imread('ml.png')
img2=cv2.imread('opencv_logo.jpg')
dst=cv2.addWeighted(img1,0.7,img2,0.3,0)
cv2.imshow('dst',dst)
cv2.waitKey(0)
cv2.destroyAllWindow()
这里包括的按位操作有:AND,OR,NOT,XOR 等。当我们提取图像的 一部分,选择非矩形 ROI 时这些操作会很有用(下一章你就会明白)。下面的 例子就是教给我们如何改变一幅图的特定区域。 我想把 OpenCV 的标志放到另一幅图像上。如果我使用加法,颜色会改 变,如果使用混合,会得到透明效果,但是我不想要透明。如果他是矩形我可 以象上一章那样使用 ROI。但是他不是矩形。但是我们可以通过下面的按位运 算实现:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
#加载图像
img1 = cv2.imread('1.jpg')
img2 = cv2.imread('1_0.jpg')
# I want to put logo on top-left corner, So I create a ROI
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]# Now create a mask of logo and create its inverse mask also
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 175, 255, cv2.THRESH_BINARY)#对图像进行二值化操作
mask_inv = cv2.bitwise_not(mask)#图像非运算
# Now black-out the area of logo in ROI # 取 roi 中与 mask 中不为零的值对应的像素的值,其他值为0
#注意这里必须有mask = mask或者mask = mask_inv,其中的mask 不能忽略
# 取 roi 中与 mask_inv 中不为零的值对应的像素的值,其他值为0 。
img1_bg = cv2.bitwise_and(roi, roi, mask=mask)
# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2,img2,mask = mask_inv)
# Put logo in ROI and modify the main image
dst = cv2.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv2.imshow('res', img1)
cv2.imshow('res0', img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
与以为信号一样,我们也可以对 2D 图像实施低通滤波(LPF),高通滤波 (HPF)等。LPF 帮助我们除去图像中的高频部分,所以去除噪音,模糊图像(边界属于高频成分,所以经常也会被一并模糊)。HPF会帮助我们去除图像中的低频部分,找到图像的边缘。
OpenCV 提供了四种模糊技术:
这是由一个归一化卷积框完成的。设定一个卷积框,卷积框覆盖区域所有像素的平 均值来代替中心元素。
下面是一个 3x3 的归一化卷积框:
将卷积框放在图像的一个像素A上,求与核对应的图像上9(3x3) 个像素的和,在取平均数,用这个平均数替代像素 A 的值。重复以上操作直到 将图像的每一个像素值都更新一边
blur = cv2.blur(img,(3,3))#卷积框大小3*3
可以看到左边的图像经过滤波之后变得平滑了,但是边界也变得模糊了。
现在把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是 相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据 距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求 加权平均数,全就是方框里的值)。
实现的函数是 cv2.GaussianBlur(arg1,arg2,,arg3,arg4)。
arg1是要处理的图像,arg2指定高斯核的宽和高(必须是奇数)。
arg3和arg4是高斯函数沿 X,Y 方向的标准 差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标 准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从 图像中去除高斯噪音(即服从正态分布的噪音)。
# -*- coding: utf-8 -*
import numpy as np
import cv2
img = cv2.imread('image/1.jpeg')
cv2.imshow('BRG',img)
GaussianBlur = cv2.GaussianBlur(img,(11,11),0)
cv2.imshow('GaussianBlur',GaussianBlur)
cv2.waitKey(0)
cv2.destroyAllWindows()
经过高斯滤波之后,加入了高斯噪点的图像噪点得到了有效的抑制,
但是高斯噪声对椒盐噪声的处理就不是很理想。
顾名思义就是用与卷积框对应像素的中值来替代中心像素的值。这个滤波 器经常用来去除椒盐噪声。前面的滤波器都是用计算得到的一个新值来取代中 心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代他。 他能有效的去除椒盐噪声。卷积核的大小也应该是一个奇数。
# -*- coding: utf-8 -*
import numpy as np
import cv2
img = cv2.imread('image\\SaltZaoSheng.png')
cv2.imshow('BRG',img)
medianblur = cv2.medianBlur(img,5)
cv2.imshow('Medianblur',medianblur)
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到,中值滤波对椒盐噪声的处理效果更好。
函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。
但是这种操作与其他滤波器相比会比较慢。
我们已经知道高斯滤波器是求 中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考 虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。
双边滤波在同时使用空间高斯权重和灰度值相似性高斯权重。空间高斯函 数确保只有邻近区域的像素对中心点有影响,灰度值相似性高斯函数确保只有 与中心像素灰度值相近的才会被用来做模糊运算。所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大
# -*- coding: utf-8 -*
import numpy as np
import cv2
img = cv2.imread('image\\GaoSiZaoSheng.png')
cv2.imshow('BRG',img)
bilateralblurred = cv2.bilateralFilter(img,9,100,100)
cv2.imshow('bilateralblurred',bilateralblurred)
cv2.waitKey(0)
cv2.destroyAllWindows()
在双边滤波处理后。噪点得到的抑制,并且图片的边缘较好的得到了保存,没有过的度失去边缘信息。
形态学操作是根据图像形状进行的简单操作。一般情况下对二值化图像进 行的操作。需要输入两个参数,一个是原始图像,第二个被称为结构化元素或 核,它是用来决定操作的性质的。两个基本的形态学操作是腐蚀和膨胀。他们 的变体构成了开运算,闭运算,梯度等。我们会以下图为例逐一介绍它们。
利用opencv内建模块
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3)
利用Numpy
NpKernel = np.uint8(np.zeros((5,5)))
for i in range(5):
NpKernel[2, i] = 1
NpKernel[i, 2] = 1
就像土壤侵蚀一样,这个操作会把前景物体的边界腐蚀掉(但是前景仍然 是白色)。这是怎么做到的呢?卷积核沿着图像滑动,如果与卷积核对应的原图 像的所有像素值都是 1,那么中心元素就保持原来的像素值,否则就变为零。
# -*- coding:utf-8 -*
import cv2
import numpy as np
img = cv2.imread('image/2.jpg',0)
# img = cv2.equalizeHist(img)
#OpenCV定义的结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
#fushi图像
eroded = cv2.erode(img,kernel)
cv2.imshow("Eroded Image",eroded);
cv2.imshow("Origin", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
未连接的地方 连接起来
与腐蚀相反,与卷积核对应的原图像的像素值中只要有一个是 1,中心元 素的像素值就是 1。所以这个操作会增加图像中的白色区域(前景)。一般在去 噪声时先用腐蚀再用膨胀。因为腐蚀在去掉白噪声的同时,也会使前景对象变 小。所以我们再对他进行膨胀。这时噪声已经被去除了,不会再回来了,但是 前景还在并会增加。
# -*- coding:utf-8 -*
import cv2
import numpy as np
img = cv2.imread('image/2.jpg',0)
# img = cv2.equalizeHist(img)
#OpenCV定义的结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
#pengzhang图像
dilated = cv2.dilate(img,kernel)
cv2.imshow("Dilated Image",dilated);
cv2.imshow("Origin", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
用于分开两个物体
先进性腐蚀再进行膨胀就叫做开运算。就像我们上面介绍的那样,它被用 来去除噪声。这
先腐蚀后膨胀==cv2.morphologyEx()
先膨胀再腐蚀。它经常被用来填充前景物体中的小洞,或者前景物体上的 小黑点。
先膨胀后腐蚀==cv2.morphologyEx()
形态学检测边缘的原理很简单,在膨胀时,图像中的物体会想周围“扩张”;腐蚀时,图像中的物体会“收缩”。比较这两幅图像,由于其变化的区域只发生在边缘。所以这时将两幅图像相减,得到的就是图像中物体的边缘。
#coding=utf-8
import cv2
import numpy
image = cv2.imread("D:/building.jpg",0);
#构造一个3×3的结构元素
element = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dilate = cv2.dilate(image, element)
erode = cv2.erode(image, element)
#将两幅图像相减获得边,第一个参数是膨胀后的图像,第二个参数是腐蚀后的图像
result = cv2.absdiff(dilate,erode);
#上面得到的结果是灰度图,将其二值化以便更清楚的观察结果
retval, result = cv2.threshold(result, 40, 255, cv2.THRESH_BINARY);
#反色,即对二值图每个像素取反
result = cv2.bitwise_not(result);
#显示图像
cv2.imshow("result",result);
cv2.waitKey(0)
cv2.destroyAllWindows()
灰度图腐蚀
用原图减去结构,选用结果中的最小值(如果有负值,则以0为最小值)作为本次输出值放置在空白图像相应的输出位置(即结构的原点位置在原图上相应的位置)。
灰度图膨胀 用原图加上结构,选用结果中的最大值
(如果有负值,则以0为最小值)作为本次输出值放置在空白图像相应的输出位置(即结构的原点位置在原图上相应的位置)。开运算为: 先腐蚀再膨胀
闭运算为: 先膨胀再腐蚀开闭运算具有幂等性。即做n次开运算和做一次开运算的结果相同,闭运算同样如此。
个人方便记忆开闭运算的操作顺序,这样理解,开运算是打开的意思,即可以理解为将图像中靠近但不相连的地方索性打开。做一次开运算,使得原来的缝隙变大。
闭运算可以理解为闭合的意思,能合并在一起的地方尽量合并。即可以理解为把图像中缝隙填满。
与名字一样,这种方法非常简单。但像素值高于阈值时,我们给这个像素 赋予一个新值(可能是白色),否则我们给它赋予另外一种颜色(也许是黑色)。
这个函数就是 cv2.threshhold(arg1,arg2,arg3,arg,4)。
原图像,原图像应该是灰度图。
用来对像素值进行分类的阈值。
当像素值高于(有时是小于)阈值时应该被赋予的新的像素值。
OpenCV 提供了多种不同的阈值方法,这是由第四个参数来决定的
• cv2.THRESH_BINARY
• cv2.THRESH_BINARY_INV
• cv2.THRESH_TRUNC
•cv2.THRESH_TOZERO
• cv2.THRESH_TOZERO_INV
有两个
retVal
以及
目标图像
# -*- coding:utf-8 -*
import cv2
import numpy as np
from matplotlib import pyplot as plt
img=cv2.imread('radial_gradient.png',0)
ret,thresh1=cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2=cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3=cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4=cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5=cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.subplot(2,3,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
在前面的部分我们使用是全局阈值,整幅图像采用同一个数作为阈值。当 时这种方法并不适应与所有情况,尤其是当同一幅图像上的不同部分的具有不 同亮度时。这种情况下我们需要采用自适应阈值。此时的阈值是根据图像上的 每一个小区域计算与其对应的阈值。因此在同一幅图像上的不同区域采用的是 不同的阈值,从而使我们能在亮度不同的情况下得到更好的结果
• Adaptive Method- 指定计算阈值的方法。
– cv2.ADPTIVE_THRESH_MEAN_C:阈值取自相邻区域的平均值
– cv2.ADPTIVE_THRESH_GAUSSIAN_C:阈值取值相邻区域 的加权和,权重为一个高斯窗口。
• Block Size - 邻域大小(用来计算阈值的区域大小)。
• C - 这就是是一个常数,阈值就等于的平均值或者加权平均值减去这个常数。
# # -*- coding:utf-8 -*
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('dave.jpg',0)
# 中值滤波
img = cv2.medianBlur(img,5)
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
#11 为 Block size, 2 为 C 值
th2=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,2)
th3=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,2)
titles = ['Original Image', 'Global Thresholding (v = 127)', 'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
for i in range(4):
plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
在第一部分中我们提到过 retVal,当我们使用 Otsu 二值化时会用到它。 那么它到底是什么呢? 在使用全局阈值时,我们就是随便给了一个数来做阈值,那我们怎么知道 我们选取的这个数的好坏呢?答案就是不停的尝试。如果是一副双峰图像(简 单来说双峰图像是指图像直方图中存在两个峰)呢?我们岂不是应该在两个峰 之间的峰谷选一个值作为阈值?这就是 Otsu 二值化要做的。简单来说就是对 一副双峰图像自动根据其直方图计算出一个阈值。(对于非双峰图像,这种方法 得到的结果可能会不理想)。 这里用到到的函数还是 cv2.threshold(),但是需要多传入一个参数 (flag):cv2.THRESH_OTSU。这时要把阈值设为 0。然后算法会找到最 优阈值,这个最优阈值就是返回值 retVal。如果不使用 Otsu 二值化,返回的 retVal 值与设定的阈值相等。 下面的例子中,输入图像是一副带有噪声的图像。第一种方法,我们设 127 为全局阈值。第二种方法,我们直接使用 Otsu 二值化。第三种方法,我 们首先使用一个 5x5 的高斯核除去噪音,然后再使用 Otsu 二值化。看看噪音 去除对结果的影响有多大吧
# -*- coding: utf-8 -*
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('noisy2.png',0)
# global thresholding
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
# Otsu's thresholding
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering
# ( 5,5 )为高斯核的大小, 0 为标准差
blur = cv2.GaussianBlur(img,(5,5),0) # 阈值一定要设为 0 !
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image','Histogram','Global Thresholding (v=127)', 'Original Noisy Image','Histogram',"Otsu's Thresholding", 'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]
for i in xrange(3):
plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')
plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)
plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])
plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')
plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])
plt.show()
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同 的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用
Point:
• 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理 或者 Canny 边界检测。
• 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图 像的话,你应该将原始图像存储到其他变量中。
• 在 OpenCV 中,查找轮廓就像在黑色背景中找白色物体。你应该记住, 要找的物体应该是白色而背景应该是黑色。
第一个是输入图像,
第二个是 轮廓检索模式,
第三个是轮廓近似方法。
第一个是图像
第二个 是轮廓
第三个是(轮廓的)层析结构。
轮廓(第二个返回值)是一个 Python 列表,其中存储这图像中的所有轮廓。
每一个轮廓都是一个 Numpy 数组,包 含对象边界点(x,y)的坐标
它的第一个参数是原始图像
第二个参数是轮廓,一 个 Python 列表。(就像findContours的第二个返回值)
第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设 置为 -1 时绘制所有轮廓)。
剩下的参数是轮廓的颜色和厚度等
我们经常需要使用摄像头捕获实时图像。OpenCV 为这中应用提供了一个 非常简单的接口。让我们使用摄像头来捕获一段视频,并把它转换成灰度视频 显示出来。从这个简单的任务开始吧。 为了获取视频,你应该创建一个 VideoCapture 对象。他的参数可以是 设备的索引号,或者是一个视频文件。设备索引号就是在指定要使用的摄像头。 一般的笔记本电脑都有内置摄像头。所以参数就是 0。你可以通过设置成 1 或 者其他的来选择别的摄像头。如果参数选择成一个视频地址,那么则会读取文件的视频流。之后,你就可以一帧一帧的捕获视频了。但是最 后,别忘了停止捕获视频
# -*- coding: utf-8 -*
"""
#- * -coding: utf - 8 - * 2 ""
# Created on Fri Jan 3 21: 06: 22 2014 4
# @ author: duan
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while (True):
#Capture frame - by - frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
• CV_CAP_PROP_POS_MSEC Current position of the video file in milliseconds.
• CV_CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next.
• CV_CAP_PROP_POS_AVI_RATIO Relative position of the video file: 0 - start of the film, 1 - end of the film.
• CV_CAP_PROP_FRAME_WIDTH Width of the frames in the video stream.
• CV_CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream.
• CV_CAP_PROP_FPS Frame rate. • CV_CAP_PROP_FOURCC 4-character code of codec.
• CV_CAP_PROP_FRAME_COUNT Number of frames in the video file.
• CV_CAP_PROP_FORMAT Format of the Mat objects returned by retrieve() .
• CV_CAP_PROP_MODE Backend-specific value indicating the current capture mode.
• CV_CAP_PROP_BRIGHTNESS Brightness of the image (only for cameras).
• CV_CAP_PROP_CONTRAST Contrast of the image (only for cameras).
• CV_CAP_PROP_SATURATION Saturation of the image (only for cameras).
• CV_CAP_PROP_HUE Hue of the image (only for cameras).
• CV_CAP_PROP_GAIN Gain of the image (only for cameras).
• CV_CAP_PROP_EXPOSURE Exposure (only for cameras).
• CV_CAP_PROP_CONVERT_RGB Boolean flags indicating whether images should be converted to RGB.
• CV_CAP_PROP_WHITE_BALANCE Currently unsupported
• CV_CAP_PROP_RECTIFICATIONRectificationflagforstereo cameras (note: only supported by DC1394 v 2.x backend currently)
谷歌翻译结果:
•CV_CAP_PROP_POS_MSEC视频文件的当前位置(以毫秒为单位)。
·CV_CAP_PROP_POS_FRAMES接下来要解码/捕获的帧的基于0的索引。
•CV_CAP_PROP_POS_AVI_RATIO视频文件的相对位置:0 - 电影的开始,1 - 电影的结束。
•CV_CAP_PROP_FRAME_WIDTH视频流中帧的宽度。
•CV_CAP_PROP_FRAME_HEIGHT视频流中帧的高度。
•CV_CAP_PROP_FPS帧速率。
•CV_CAP_PROP_FOURCC编解码器的4字符代码。
•CV_CAP_PROP_FRAME_COUNT视频文件中的帧数。
•CV_CAP_PROP_FORMAT
retrieve()返回的Mat对象的格式。
•CV_CAP_PROP_MODE后端特定值,指示当前捕获模式。
•CV_CAP_PROP_BRIGHTNESS图像的亮度(仅适用于相机)。
•CV_CAP_PROP_CONTRAST图像对比度(仅适用于相机)。
•CV_CAP_PROP_SATURATION图像饱和度(仅适用于相机)。
•CV_CAP_PROP_HUE图像的色调(仅适用于相机)。
•CV_CAP_PROP_GAIN图像的增益(仅适用于相机)。
•CV_CAP_PROP_EXPOSURE曝光(仅适用于相机)。
•CV_CAP_PROP_CONVERT_RGB布尔值指示是否应将图像转换为RGB。
•CV_CAP_PROP_WHITE_BALANCE当前不受支持
•CV_CAP_PROP_RECTIFICATIONRecti fi
cation fl agforstereo相机(注意:目前仅支持DC1394 v 2.x后端)
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist
| 参数 | 参数说明 |
| images | 该参数是源数组,他们深度与尺寸需要相同 |
| channels | 该参数是dims个通道列表,用来计算直方图 |
| mask | 可选 |
| histSize | 表示这个直方图分成多少份(即多少个直方柱) |
| ranges | 参数是表示直方图中各个像素的值 |
import cv2
import numpy as np
img = cv2.imread("1.jpeg")
b, g, r = cv2.split(img)
def calcAndDrawHist(image, color):
hist= cv2.calcHist([image], [0], None, [256], [0.0,255.0])
minVal, maxVal, minLoc, maxLoc = cv2.minMaxLoc(hist)
histImg = np.zeros([256,256,3], np.uint8)
hpt = int(0.9* 256);
for h in range(256):
intensity = int(hist[h]*hpt/maxVal)
cv2.line(histImg,(h,256), (h,256-intensity), color)
return histImg;
histImgB = calcAndDrawHist(b, [255, 0, 0])
histImgG = calcAndDrawHist(g, [0, 255, 0])
histImgR = calcAndDrawHist(r, [0, 0, 255])
cv2.imshow("histImgB", histImgB)
cv2.imshow("histImgG", histImgG)
cv2.imshow("histImgR", histImgR)
cv2.imshow("Img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread('D:/lena.jpg')
h = np.zeros((256,256,3)) #创建用于绘制直方图的全0图像
bins = np.arange(256).reshape(256,1) #直方图中各bin的顶点位置
color = [ (255,0,0),(0,255,0),(0,0,255) ] #BGR三种颜色
for ch, col in enumerate(color):
originHist = cv2.calcHist([img],[ch],None,[256],[0,256])
cv2.normalize(originHist, originHist,0,255*0.9,cv2.NORM_MINMAX)
hist=np.int32(np.around(originHist))
pts = np.column_stack((bins,hist))
cv2.polylines(h,[pts],False,col)
h=np.flipud(h)
cv2.imshow('colorhist',h)
cv2.waitKey(0)
• img:你想要绘制图形的那幅图像。
• color:形状的颜色。以RGB为例,需要传入一个元组,例如: (255,0,0) 代表蓝色。对于灰度图只需要传入灰度值。
• thickness:线条的粗细。如果给一个闭合图形设置为 -1,那么这个图形就会被填充。默认值是 1
• linetype:线条的类型, 8连接,抗锯齿等。默认情况是8连接。cv2.LINE_AA
为抗锯齿,这样看起来会非常平滑。
指定起点终点
cv2.line(img,(0,0),(511,511),(255,0,0),5)
指定左上角顶点和右下角顶点的坐标
cv2.rectangle(img,(0,0),(510,510),(0,255,0),3)
cv2.rectangle(img,(0,0),(510,510),(0,255,0),3)
font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,'OpenCV',(10,500), font, 4,(255,255,255),2)
警告:所有的绘图函数的返回值都是 None,所以不能使用 img = cv2.line(img,(0,0),(511,511),(255,0,0),5)。
# -*- coding: utf-8 -*
import cv2
import numpy as np
# 当鼠标按下时变为True
drawing = False
# 如果 mode 为true绘制矩形。 按下 'm'变成绘制曲线。
mode = True
ix, iy = -1, -1
#创建回调函数
def draw_circle(event, x, y, flags, param):
global ix, iy, drawing, mode
# 当按下左键是返回起始位置坐标
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
# 当鼠标左键按下并移动是绘制图形。 event 可以查看移动, flag查看是否按下
elif event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else :
#绘制圆圈, 小圆点连在一起就成了线, 3 代表了笔画的粗细
cv2.circle(img, (x, y), 3, (0, 0, 255), -1)
# 下面注释掉的代码是起始点为圆心, 起点到终点为半径的
# r = int(np.sqrt((x - ix) * * 2 + (y - iy) * * 2))
# cv2.circle(img, (x, y), r, (0, 0, 255), -1)
# 当鼠标松开停止绘画。
elif event == cv2.EVENT_LBUTTONUP:
drawing == False
if mode == True:
cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)
else :
cv2.circle(img, (x, y), 5, (0, 0, 255), -1)
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while (1):
cv2.imshow('image', img)
k = cv2.waitKey(1) & 0xFF
if k == ord('m'):
mode = not mode
elif k == 27:
break
import cv2
import numpy as np
def nothing(x):
pass
# 创建一个黑色背景的窗口
img = np.zeros((300,512,3), np.uint8)
cv2.namedWindow('image')
# 创建改变颜色的滚动条
cv2.createTrackbar('R','image',0,255,nothing)
cv2.createTrackbar('G','image',0,255,nothing)
cv2.createTrackbar('B','image',0,255,nothing)
# 创建控制函数的开关
switch = '0 : OFF \n1 : ON'
cv2.createTrackbar(switch, 'image',0,1,nothing)
while(1):
cv2.imshow('image',img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# 获取四个滚动条的位置
r = cv2.getTrackbarPos('R','image')
g = cv2.getTrackbarPos('G','image')
b = cv2.getTrackbarPos('B','image')
s = cv2.getTrackbarPos(switch,'image')
if s == 0:
img[:] = 0
else:
img[:] = [b,g,r]#把滚动条里的颜色值赋给图片
cv2.destroyAllWindows()
# 这里建立了一个简单的样例来现实用户指定的颜色。用户使用三个滚动条来指
# 定B,G,R值,同时用户选择的颜色会显示在窗口当中。用户拖动滚动条会关联到窗口
# 中颜色的改变。初始默认的颜色会被设置为黑色。
# 对于cv2.getTrackbarPos()函数,第一个参数是滚动条的名称,第二个个参数是
# 关联的窗口名称,第三个参数是缺省值,第四个参数是是最大值,第五个参数是执
# 行所有改变值的回调函数。回调函数总是有一个缺省参数,这个参数是滚动条的位
# 置。在本例子当中,函数该函数不做任何事情,简单略过即可。
# 滚动条另外一个重要的应用是用来作为按钮或者开关。默认情况下,opencv里面没
# 有按钮功能。所以用户需要使用滚动条来实现这样的一个功能。在本例子当中,我
# 们创建了一个开关,这个开关控制这个应用程序的颜色变化功能是否开启,如果开
# 关功能关闭,那么屏幕一直都是黑色的
首先我们需要读入一幅图像
img=cv2.imread('1.jpg'
你可以根据像素的行和列的坐标获取他的像素值
px=img[100,100]
print (px)
## [57 63 68]
blue=img[100,100,0]
print (blue)
## 5
警告:Numpy 是经过优化了的进行快速矩阵运算的软件包。所以我们不推荐 逐个获取像素值并修改,这样会很慢,能有矩阵运算就不要用循环。
注意:上面提到的方法被用来选取矩阵的一个区域,比如说前5行的后3列。对于获取每一个像素值,也许使用Numpy的array.item()和array.itemset() 会更好。但是返回值是标量。如果你想获得所有B, G, R的值,你需要使用array.item()分割他们。
img.shape 可以获取图像的形状。返回值是一个包含行数,列数, 通道数的元组
img.size 可以返回图像的像素数目
img.dtype 返回的是图像的数据类型.
如果你想在图像周围创建一个边,就像相框一样,你可以使用cv2.copyMakeBorder() 函数。这经常在卷积运算或 0 填充时被用到。这个函数包括如下参数:
• src 输入图像
• top, bottom, left, right 对应边界的像素数目。
• borderType 要添加那种类型的边界,类型如下
– cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要 下一个参数(value)。
– cv2.BORDER_REFLECT边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb
– cv2.BORDER_REFLECT_101orcv2.BORDER_DEFAULT 跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba
– cv2.BORDER_REPLICATE重复最后一个元素。例如: aaaaaa| abcdefgh|hhhhhhh
– cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh| abcdefgh|abcdefg
• value 边界颜色,如果边界的类型是 cv2.BORDER_CONSTANT
# -*- coding: utf-8 -*-
import cv2
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255, 0, 0]
img1 = cv2.imread('1.jpeg')
b, g, r = cv2.split(img1)
img1 = cv2.merge([r,g,b])
replicate = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=BLUE)
plt.subplot(231), plt.imshow(img1, 'gray'), plt.title('ORIGINAL')
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE')
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT')
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101')
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP')
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT')
plt.show()
一般情况下,我们要处理是一副具有固定分辨率的图像。但是有些情况下, 我们需要对同一图像的不同分辨率的子图像进行处理。比如,我们要在一幅图 像中查找某个目标,比如脸,我们不知道目标在图像中的尺寸大小。这种情况 下,我们需要创建创建一组图像,这些图像是具有不同分辨率的原始图像。我 们把这组图像叫做图像金字塔(简单来说就是同一图像的不同分辨率的子图集 合)。如果我们把最大的图像放在底部,最小的放在顶部,看起来像一座金字 塔,故而得名图像金字塔。 有两类图像金字塔:高斯金字塔和拉普拉斯金字塔。 高斯金字塔的顶部是通过将底部图像中的连续的行和列去除得到的。顶 部图像中的每个像素值等于下一层图像中 5 个像素的高斯加权平均值。这样 操作一次一个 MxN 的图像就变成了一个 M/2xN/2 的图像。所以这幅图像 的面积就变为原来图像面积的四分之一。这被称为 Octave。连续进行这样 的操作我们就会得到一个分辨率不断下降的图像金字塔。我们可以使用函数 cv2.pyrDown() 和 cv2.pyrUp() 构建图像金字塔。 函数 cv2.pyrDown() 从一个高分辨率大尺寸的图像向上构建一个金子塔 (尺寸变小,分辨率降低)
img = cv2.imread('messi5.jpg')
lower_reso = cv2.pyrDown(higher_reso)
读入两幅图像,苹果和句子
构建苹果和橘子的高斯金字塔(6 层)
根据高斯金字塔计算拉普拉斯金字塔
在拉普拉斯的每一层进行图像融合(苹果的左边与橘子的右边融合)
根据融合后的图像金字塔重建原始图像
#-*- coding:utf-8 -*
import cv2
import numpy as np
import sys
A = cv2.imread('D:\A_project\opencv3\\apple.jpg')
B = cv2.imread('D:\A_project\opencv3\orange.jpg')
# generate Gaussian pyramid for A
G = A.copy()
gpA = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpA.append(G)
# generate Gaussian pyramid for B
G = B.copy()
gpB = [G]
for i in range(6):
G = cv2.pyrDown(G)
gpB.append(G)
# generate Laplacian Pyramid for A
lpA = [gpA[5]]
for i in range(5, 0, -1):
GE = cv2.pyrUp(gpA[i])
L = cv2.subtract(gpA[i - 1], GE)
lpA.append(L)
# generate Laplacian Pyramid for B
lpB = [gpB[5]]
for i in range(5, 0, -1):
GE = cv2.pyrUp(gpB[i])
L = cv2.subtract(gpB[i - 1], GE)
lpB.append(L)
# Now add left and right halves of images in each level #numpy.hstack(tup) #Take a sequence of arrays and stack them horizontally #to make a single array.
LS = []
for la, lb in zip(lpA, lpB):
rows, cols, dpt = la.shape
ls = np.hstack((la[:, 0:cols // 2], lb[:, cols // 2:]))
LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# image with direct connecting each half
real = np.hstack((A[:, :cols // 2], B[:, cols // 2:]))
cv2.imwrite('Pyramid_blending2.jpg', ls_)
cv2.imwrite('Direct_blending.jpg', real)
在OpenCV-Python中,Laplace算子的函数原型如下:
dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
#前两个是必须的参数:
#第一个参数是需要处理的图像;
#第二个参数是图像深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度
#其后是可选的参数:
#dst不用解释了;
#ksize是算子的大小,必须为1、3、5、7。默认为1。
#scale是缩放导数的比例常数,默认情况下没有伸缩系数;
#delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
#borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread("D:/lion.jpg", 0)
gray_lap = cv2.Laplacian(img,cv2.CV_16S,ksize = 3)
dst = cv2.convertScaleAbs(gray_lap)
cv2.imshow('laplacian',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图
拉普拉斯算法处理
Sobel算子是像素图像边缘检测中最重要的算子之一,在机器学习、数字媒体、计算机视觉等信息科技领域起着举足轻重的作用。在技术上,它是一个离散的一阶差分算子,用来计算图像亮度函数的一阶梯度之近似值。在图像的任何一点使用此算子,将会产生该点对应的梯度矢量或是其法矢量。
函数原型
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])第一个参数是需要处理的图像; 第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。 其后是可选的参数:dst不用解释了; ksize是Sobel算子的大小,必须为1、3、5、7。 scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
#coding=utf-8
import cv2
import numpy as np
img = cv2.imread("D:/lion.jpg", 0)
x = cv2.Sobel(img,cv2.CV_16S,1,0)
y = cv2.Sobel(img,cv2.CV_16S,0,1)
absX = cv2.convertScaleAbs(x) # 转回uint8
absY = cv2.convertScaleAbs(y)
dst = cv2.addWeighted(absX,0.5,absY,0.5,0)
cv2.imshow("absX", absX)
cv2.imshow("absY", absY)
cv2.imshow("Result", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
原图
Sobel处理